package com.yhb.channel.impl.ANYPAY.http.utils;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.function.Function;

/**
 * @Description: AES加密解密算法
 * @author: dengzhixin
 * @date 2017年3月22日 上午11:36:37
 *
 */
public class AnyPayAESUtil {

	/**
	 * 加密算法
	 */
	private static final String ALGORITHM = "AES";

	/**
	 * 默认编码方式
	 */
	private static final String DEFAULT_CHARSET = "utf-8";

	private static byte[] getIvKey(byte[] iv, PaddingMode paddingMode) {
		byte[] ivKey = null;
		if (paddingMode == PaddingMode.AES_CBC && null != iv && iv.length >= 16) {
			ivKey = new byte[16];
			System.arraycopy(iv, 0, ivKey, 0, 16);
		}
		return ivKey;
	}

	private static Function<String, byte[]> pre64 = (str) -> {
		try {
			return new BASE64Decoder().decodeBuffer(str);
		} catch (Exception e) {
		}
		return null;
	};

	private static Function<byte[], String> suf = (byt) -> {
		try {
			return new String(byt, DEFAULT_CHARSET);
		} catch (Exception e) {
		}
		return null;
	};

	public static String base64CbcDecrypt(String content, String encKey) throws Exception {
		return decrypt(content, encKey, encKey, pre64, suf, PaddingMode.AES_CBC);
	}


	/**
	 * decrypt with key
	 *
	 * @param content
	 * @param encKey
	 * @param iv
	 * @param pre
	 * @param suf
	 * @param paddingMode
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String content, String encKey, String iv, Function<String, byte[]> pre,
								  Function<byte[], String> suf, PaddingMode paddingMode) throws Exception {
		byte[] data = pre.apply(content);
		byte[] key = encKey.getBytes(DEFAULT_CHARSET);
		byte[] ivKey = StringUtils.isNotBlank(iv) ? getIvKey(iv.getBytes(), paddingMode) : null;
		byte[] encrypted = process(data, key, ivKey, Cipher.DECRYPT_MODE, paddingMode);
		return suf.apply(encrypted);
	}

	/**
	 * main encrypt/decrypt process
	 *
	 * @param data
	 * @param key
	 * @param oprMode
	 * @param paddingMode
	 * @return
	 * @throws Exception
	 */
	private static byte[] process(byte[] data, byte[] key, byte[] spec, int oprMode, PaddingMode paddingMode)
			throws Exception {
		if (null == key || (key.length != 16 && key.length != 24 && key.length != 32)) {
			throw new Exception("key长度必须是16或者24或者32");
		}

		SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);

		IvParameterSpec iv = null;
		if (null != spec && spec.length > 0) {
			iv = new IvParameterSpec(spec);
		}

		Cipher cipher = Cipher.getInstance(paddingMode.getType());
		cipher.init(oprMode, keySpec, iv);
		return cipher.doFinal(data);
	}

	public static void main(String[] args) throws Exception {

		String sKey = "BNrEbEQeF3Naa64x";

		// 需要解密的字串
		String content = "Kt5Sqs7Qi7s5m0iW9A9CBUCAIvlhxHjlCYYA5TPLxzwMWDBUfzOAlKcH65IYpRTrGa/Czcc8gkMr\\nwvjqS/cXzx9SRUDLXJSoKZ7QElBNTIzM2knyxuuzpFjm8yVUn1dpFObv6b2MWrN3G0CqVMIqtqHT\\nYauEojI5Conpq0rgdKzin1qMwxznHl7bntz5TmTCLDiFKwzcLaJA2EyiiW9XTF6x4svmXQn5w9YK\\nBaHhgZLXd9n1E35KGOlqhACuvamO".replace("\n", "");

		String deString = AnyPayAESUtil.base64CbcDecrypt(content, sKey);
		System.out.println("解密后的字串是：" + deString);
	}
}
